package com.ethink.warehouse.manager;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Pair;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.id.generator.IdGenerator;
import com.ethink.warehouse.api.enums.*;
import com.ethink.warehouse.api.info.MateInventoryCxDetailLogInfo;
import com.ethink.warehouse.api.info.MateInventoryDetailOrderInfo;
import com.ethink.warehouse.api.request.MateInventoryLockLogAddRequest;
import com.ethink.warehouse.api.request.MateInventoryOrderAddT51OrT91Request;
import com.ethink.warehouse.api.request.MateInventoryOrderAddT51OrT91RequestItem;
import com.ethink.warehouse.api.request.MateInventoryOutRequest;
import com.ethink.warehouse.api.response.MateInventoryOutResponse;
import com.ethink.warehouse.common.entity.*;
import com.ethink.warehouse.common.mapper.*;
import com.ethink.warehouse.common.model.MateInventoryAutoAdjustItemModel;
import com.ethink.warehouse.service.MateInventoryDetailOrderService;
import com.ethink.warehouse.service.MateInventoryLockLogService;
import com.ethink.warehouse.service.MateInventoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author default
 * @date 2022-11-10
 */
@Slf4j
@Component
public class MateInventoryManager {

    @Autowired
    private MateInventoryService mateInventoryService;
    @Autowired
    private MateInventoryMapper mateInventoryMapper;
    @Autowired
    private MateInventoryOrderMapper mateInventoryOrderMapper;
    @Autowired
    private MateInventoryDetailOrderMapper mateInventoryDetailOrderMapper;
    @Autowired
    private LogisticsTraceDetailOrderMapper logisticsTraceDetailOrderMapper;
    @Autowired
    private MateInventoryLockLogMapper mateInventoryLockLogMapper;
    @Autowired
    private MateInventoryDetailOrderService mateInventoryDetailOrderService;
    @Autowired
    private MateInventoryLockLogService mateInventoryLockLogService;
    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private MatePurchaseCodeMapper matePurchaseCodeMapper;

    public List<Object[]> convert(List<LogisticsTraceApplyOrder> applyOrderList,
                                  List<LogisticsTraceApplyDetailOrder> logisticsTraceApplyDetailOrderList,
                                  List<LogisticsTraceDetailOrder> logisticsTraceDetailOrderList) {
        Map<String, LogisticsTraceApplyOrder> logisticsTraceApplyOrderMap =
                applyOrderList.stream().collect(Collectors.toMap(
                        LogisticsTraceApplyOrder::getApplyOrderNo, info -> info));
        Map<Long, LogisticsTraceApplyDetailOrder> logisticsTraceApplyDetailOrderMap =
                logisticsTraceApplyDetailOrderList.stream().collect(Collectors.toMap(
                        LogisticsTraceApplyDetailOrder::getId, info -> info));
        return logisticsTraceDetailOrderList.stream().map(info -> {
            LogisticsTraceApplyOrder applyOrder = logisticsTraceApplyOrderMap.get(info.getApplyOrderNo());
            LogisticsTraceApplyDetailOrder applyDetailOrder = logisticsTraceApplyDetailOrderMap.get(info.getApplyDetailId());
            Object[] objects = new Object[3];
            objects[0] = applyOrder;
            objects[1] = applyDetailOrder;
            objects[2] = info;
            return objects;
        }).collect(Collectors.toList());
    }

    /**
     * 采购入库,这里需要获取采购单以及对应的销售需求渠道
     */
    @Transactional(rollbackFor = Exception.class)
    public void t11(LogisticsTraceOrder traceOrder, List<LogisticsTraceApplyOrder> applyOrderList,
                    List<LogisticsTraceApplyDetailOrder> applyDetailOrderList,
                    List<LogisticsTraceDetailOrder> detailOrderList) {
        List<Object[]> traceDetailOrderList = convert(applyOrderList, applyDetailOrderList, detailOrderList);
        // 创建入库单
        // 创建入库明细
        // 创建库存
        MateInventoryOrder mateInventoryOrder = new MateInventoryOrder();
        mateInventoryOrder.setOrderNo(idGenerator.rk());
        mateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizOrderNo(traceOrder.getOrderNo());
        mateInventoryOrder.setSourceOrderType(traceOrder.getSourceOrderType());
        mateInventoryOrder.setCreateUserCode(traceOrder.getCreateUserCode());
        mateInventoryOrder.setCreateUserName(traceOrder.getCreateUserName());
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        int index = 0;
        for (Object[] array : traceDetailOrderList) {
            LogisticsTraceApplyOrder applyOrder = (LogisticsTraceApplyOrder) array[0];
            LogisticsTraceApplyDetailOrder applyDetailOrder = (LogisticsTraceApplyDetailOrder) array[1];
            LogisticsTraceDetailOrder traceDetailOrder = (LogisticsTraceDetailOrder) array[2];
            if (traceDetailOrder.getMateInventoryId() != null) {
                // 验证没有生成过对应的批次库存
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "入库已完成，不能重复操作");
            }
            if (index == 0) {
                mateInventoryOrder.setSubject(applyOrder.getSubject());
                mateInventoryOrder.setSubWarehouseCode(traceDetailOrder.getSubWarehouseCode());
                mateInventoryOrderMapper.insert(mateInventoryOrder);
            }
            String saleSubChannel = applyOrder.getSaleSubChannel();
            String subWarehouseCode = traceDetailOrder.getSubWarehouseCode();
            Integer inventoryType = traceDetailOrder.getInventoryType();
            String mateSku = traceDetailOrder.getMateSku();
            Integer actualInQty = traceDetailOrder.getActualInQty();
            String purchaseCode = idGenerator.pc();
            MatePurchaseCode matePurchaseCode = new MatePurchaseCode();
            matePurchaseCode.setMateSku(mateSku);
            matePurchaseCode.setPurchaseCode(purchaseCode);
            // 采购单信息
            matePurchaseCode.setPurchaseOrderNo(traceDetailOrder.getPurchaseOrderNo());
            matePurchaseCode.setPurchaseDetailOrderNo(traceDetailOrder.getPurchaseDetailOrderNo());
            matePurchaseCode.setCostPrice(traceDetailOrder.getCostPrice());
            // 物流提供信息
            matePurchaseCode.setProduceCode(traceDetailOrder.getProduceCode());
            matePurchaseCode.setCountryOfOrigin(traceDetailOrder.getCountryOfOrigin());
            matePurchaseCode.setProductDate(traceDetailOrder.getProductDate());
            matePurchaseCode.setExpireDate(traceDetailOrder.getExpireDate());
            matePurchaseCode.setType(PurchaseCodeTypeEnum.T1.getIntValue());
            matePurchaseCodeMapper.insert(matePurchaseCode);
            // 入库单明细
            MateInventoryDetailOrder mateInventoryDetailOrder = new MateInventoryDetailOrder();
            mateInventoryDetailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
            mateInventoryDetailOrder.setSourceOrderNo(applyOrder.getSourceOrderNo());
            mateInventoryDetailOrder.setSourceDetailOrderNo(applyOrder.getSourceDetailOrderNo());
            mateInventoryDetailOrder.setMateSku(mateSku);
            mateInventoryDetailOrder.setPurchaseCode(purchaseCode);
            mateInventoryDetailOrder.setInventoryType(inventoryType);
            mateInventoryDetailOrder.setSaleSubChannel(saleSubChannel);
            mateInventoryDetailOrder.setActualInQty(actualInQty);
            mateInventoryDetailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            mateInventoryDetailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            mateInventoryDetailOrder.setProductDate(matePurchaseCode.getProductDate());
            mateInventoryDetailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            mateInventoryDetailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            mateInventoryDetailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            mateInventoryDetailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            MateInventory mateInventory = new MateInventory();
            mateInventory.setMateSku(mateSku);
            mateInventory.setSubWarehouseCode(subWarehouseCode);
            mateInventory.setPurchaseCode(purchaseCode);
            mateInventory.setInventoryType(inventoryType);
            mateInventory.setSaleSubChannel(saleSubChannel);
            mateInventory.setAvailableQty(actualInQty);
            mateInventory.setLockQty(0);
            mateInventory.setOnPassageQty(0);
            mateInventoryMapper.insert(mateInventory);
            mateInventoryDetailOrder.setMateInventoryId(mateInventory.getId());
            mateInventoryDetailOrderList.add(mateInventoryDetailOrder);
            // 跟进跟进明细表mateInventoryId, 采购批次
            logisticsTraceDetailOrderMapper.update(null, new LambdaUpdateWrapper<LogisticsTraceDetailOrder>()
                    .eq(LogisticsTraceDetailOrder::getId, traceDetailOrder.getId())
                    .set(LogisticsTraceDetailOrder::getMateInventoryId, mateInventory.getId())
                    .set(LogisticsTraceDetailOrder::getPurchaseCode, mateInventory.getPurchaseCode())
            );
            index++;
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
    }

    /**
     * 预售退货，销售退货,调拨入库 提供sku，采购批次，渠道
     *
     * @param traceOrder
     * @param applyOrderList
     * @param applyDetailOrderList
     * @param detailOrderList
     */
    @Transactional(rollbackFor = Exception.class)
    public void t41OrT71OrT31(LogisticsTraceOrder traceOrder, List<LogisticsTraceApplyOrder> applyOrderList,
                              List<LogisticsTraceApplyDetailOrder> applyDetailOrderList,
                              List<LogisticsTraceDetailOrder> detailOrderList) {
        List<Object[]> traceDetailOrderList = convert(applyOrderList, applyDetailOrderList, detailOrderList);
        // 创建入库单
        // 创建入库明细
        // 创建库存
        MateInventoryOrder mateInventoryOrder = new MateInventoryOrder();
        mateInventoryOrder.setOrderNo(idGenerator.rk());
        mateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizOrderNo(traceOrder.getOrderNo());
        mateInventoryOrder.setSourceOrderType(traceOrder.getSourceOrderType());
        mateInventoryOrder.setCreateUserCode(traceOrder.getCreateUserCode());
        mateInventoryOrder.setCreateUserName(traceOrder.getCreateUserName());
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        int index = 0;
        for (Object[] array : traceDetailOrderList) {
            LogisticsTraceApplyOrder applyOrder = (LogisticsTraceApplyOrder) array[0];
            LogisticsTraceApplyDetailOrder applyDetailOrder = (LogisticsTraceApplyDetailOrder) array[1];
            LogisticsTraceDetailOrder traceDetailOrder = (LogisticsTraceDetailOrder) array[2];
            if (traceDetailOrder.getMateInventoryId() != null) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "入库已完成，不能重复操作");
            }
            if (index == 0) {
                mateInventoryOrder.setSubject(applyOrder.getSubject());
                mateInventoryOrder.setSubWarehouseCode(applyOrder.getSourceSubWarehouseCode());
                mateInventoryOrderMapper.insert(mateInventoryOrder);
            }
            String subWarehouseCode = traceDetailOrder.getSubWarehouseCode();
            Integer inventoryType = traceDetailOrder.getInventoryType();
            String mateSku = traceDetailOrder.getMateSku();
            String purchaseCode = traceDetailOrder.getPurchaseCode();
            String saleSubChannel = applyOrder.getSaleSubChannel();
            Integer actualInQty = traceDetailOrder.getActualInQty();
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                    new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getMateSku, mateSku)
                            .eq(MatePurchaseCode::getPurchaseCode, purchaseCode));
            MateInventory mateInventory = mateInventoryMapper.selectOne(new LambdaQueryWrapper<MateInventory>()
                    .eq(MateInventory::getSubWarehouseCode, subWarehouseCode)
                    .eq(MateInventory::getMateSku, mateSku)
                    .eq(MateInventory::getInventoryType, inventoryType)
                    .eq(MateInventory::getPurchaseCode, purchaseCode)
                    .eq(MateInventory::getSaleSubChannel, saleSubChannel)
            );
            if (mateInventory == null) {
                mateInventory = new MateInventory();
                mateInventory.setMateSku(mateSku);
                mateInventory.setSubWarehouseCode(subWarehouseCode);
                mateInventory.setPurchaseCode(purchaseCode);
                mateInventory.setInventoryType(inventoryType);
                mateInventory.setSaleSubChannel(saleSubChannel);
                mateInventory.setAvailableQty(actualInQty);
                mateInventory.setLockQty(0);
                mateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(mateInventory);
            } else {
                mateInventoryMapper.update(null,
                        new LambdaUpdateWrapper<MateInventory>()
                                .eq(MateInventory::getId, mateInventory.getId())
                                .set(MateInventory::getAvailableQty, mateInventory.getAvailableQty() + actualInQty)
                );
            }
            MateInventoryDetailOrder mateInventoryDetailOrder = new MateInventoryDetailOrder();
            mateInventoryDetailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
            mateInventoryDetailOrder.setSourceOrderNo(applyOrder.getSourceOrderNo());
            mateInventoryDetailOrder.setSourceDetailOrderNo(applyOrder.getSourceDetailOrderNo());
            mateInventoryDetailOrder.setMateSku(mateSku);
            mateInventoryDetailOrder.setInventoryType(inventoryType);
            mateInventoryDetailOrder.setSaleSubChannel(saleSubChannel);
            mateInventoryDetailOrder.setPurchaseCode(matePurchaseCode.getPurchaseCode());
            mateInventoryDetailOrder.setActualInQty(actualInQty);
            mateInventoryDetailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            mateInventoryDetailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            mateInventoryDetailOrder.setProductDate(matePurchaseCode.getProductDate());
            mateInventoryDetailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            mateInventoryDetailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            mateInventoryDetailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            mateInventoryDetailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            mateInventoryDetailOrder.setMateInventoryId(mateInventory.getId());
            mateInventoryDetailOrderList.add(mateInventoryDetailOrder);
            // 跟进跟进明细表mateInventoryId
            logisticsTraceDetailOrderMapper.update(null, new LambdaUpdateWrapper<LogisticsTraceDetailOrder>()
                    .eq(LogisticsTraceDetailOrder::getId, traceDetailOrder.getId())
                    .set(LogisticsTraceDetailOrder::getMateInventoryId, mateInventory.getId())
            );
            index++;
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
    }

    /**
     * 预售退货，销售退货,调拨入库 提供sku，采购批次，渠道
     */
    @Transactional(rollbackFor = Exception.class)
    public List<MateInventoryAutoAdjustItemModel> t51OrT91(MateInventoryOrderAddT51OrT91Request request) {
        // 创建入库单
        // 创建入库明细
        // 创建库存
        List<MateInventoryAutoAdjustItemModel> itemModels = new ArrayList<>();
        MateInventoryOrder mateInventoryOrder = new MateInventoryOrder();
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        mateInventoryOrder.setOrderNo(idGenerator.rk());
        mateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        BeanUtils.copyProperties(request, mateInventoryOrder);
        mateInventoryOrderMapper.insert(mateInventoryOrder);
        for (MateInventoryOrderAddT51OrT91RequestItem item : request.getItems()) {
            String subWarehouseCode = request.getSubWarehouseCode();
            Integer inventoryType = item.getInventoryType();
            String mateSku = item.getMateSku();
            String purchaseCode = item.getPurchaseCode();
            String saleSubChannel = item.getSaleSubChannel();
            Integer actualInQty = item.getActualInQty();
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                    new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getMateSku, mateSku)
                            .eq(MatePurchaseCode::getPurchaseCode, purchaseCode));
            MateInventory mateInventory = mateInventoryMapper.selectOne(new LambdaQueryWrapper<MateInventory>()
                    .eq(MateInventory::getSubWarehouseCode, subWarehouseCode)
                    .eq(MateInventory::getMateSku, mateSku)
                    .eq(MateInventory::getInventoryType, inventoryType)
                    .eq(MateInventory::getPurchaseCode, purchaseCode)
                    .eq(MateInventory::getSaleSubChannel, saleSubChannel)
            );
            if (mateInventory == null) {
                mateInventory = new MateInventory();
                mateInventory.setMateSku(mateSku);
                mateInventory.setSubWarehouseCode(subWarehouseCode);
                mateInventory.setPurchaseCode(purchaseCode);
                mateInventory.setInventoryType(inventoryType);
                mateInventory.setSaleSubChannel(saleSubChannel);
                mateInventory.setAvailableQty(actualInQty);
                mateInventory.setLockQty(0);
                mateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(mateInventory);
            } else {
                mateInventoryMapper.update(null,
                        new LambdaUpdateWrapper<MateInventory>()
                                .eq(MateInventory::getId, mateInventory.getId())
                                .set(MateInventory::getAvailableQty, mateInventory.getAvailableQty() + actualInQty)
                );
            }
            MateInventoryDetailOrder mateInventoryDetailOrder = new MateInventoryDetailOrder();
            mateInventoryDetailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
            mateInventoryDetailOrder.setSourceOrderNo(item.getSourceOrderNo());
            mateInventoryDetailOrder.setSourceDetailOrderNo(item.getSourceDetailOrderNo());
            mateInventoryDetailOrder.setMateSku(mateSku);
            mateInventoryDetailOrder.setInventoryType(inventoryType);
            mateInventoryDetailOrder.setSaleSubChannel(saleSubChannel);
            mateInventoryDetailOrder.setPurchaseCode(purchaseCode);
            mateInventoryDetailOrder.setActualInQty(actualInQty);
            mateInventoryDetailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            mateInventoryDetailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            mateInventoryDetailOrder.setProductDate(matePurchaseCode.getProductDate());
            mateInventoryDetailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            mateInventoryDetailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            mateInventoryDetailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            mateInventoryDetailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            mateInventoryDetailOrder.setMateInventoryId(mateInventory.getId());
            mateInventoryDetailOrderList.add(mateInventoryDetailOrder);
            if (StringUtils.isNotBlank(item.getRealProduceCode()) && !matePurchaseCode.getProduceCode().equals(item.getRealProduceCode())) {
                // 采购批次不一致，需要矫正批次
                MateInventoryAutoAdjustItemModel itemModel = new MateInventoryAutoAdjustItemModel();
                itemModel.setBeforeMateInventory(mateInventoryDetailOrder);
                itemModel.setRealProduceCode(item.getRealProduceCode());
                itemModel.setSourceOrderNo(item.getSourceOrderNo());
                itemModel.setSourceDetailOrderNo(item.getSourceDetailOrderNo());
                itemModels.add(itemModel);
            }
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return itemModels;
    }

    /**
     * 库存锁定数量更新
     */
    @Transactional(rollbackFor = Exception.class)
    public void lockMateInventory(List<MateInventoryLockLogAddRequest> requests) {
        for (MateInventoryLockLogAddRequest request : requests) {
            MateInventoryLockLog mateInventoryLockLog = mateInventoryLockLogMapper.selectOne(
                    new LambdaQueryWrapper<MateInventoryLockLog>()
                            .eq(MateInventoryLockLog::getOrderType, request.getOrderType())
                            .eq(MateInventoryLockLog::getMateInventoryId, request.getMateInventoryId())
                            .eq(MateInventoryLockLog::getSourceOrderNo, request.getSourceOrderNo())
                            .eq(MateInventoryLockLog::getLockStatus, MateInventoryLockLogLockStatusEnum.S1.getIntValue())
                            .eq(MateInventoryLockLog::getSourceDetailOrderNo, request.getSourceDetailOrderNo()));
            if (mateInventoryLockLog != null) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "订单已锁定库存，不能重复操作");
            }
            MateInventory mateInventory = mateInventoryMapper.selectById(request.getMateInventoryId());
            if (mateInventory.getAvailableQty() < request.getLockQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法锁定");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, request.getMateInventoryId())
                    .set(MateInventory::getLockQty, mateInventory.getLockQty() + request.getLockQty())
                    .set(MateInventory::getAvailableQty, mateInventory.getAvailableQty() - request.getLockQty())
            );
        }
        mateInventoryLockLogService.batchSave(requests);
    }


    /**
     * 库存锁定释放
     */
    @Transactional(rollbackFor = Exception.class)
    public void releaseLockMateInventory(List<MateInventoryLockLogAddRequest> requests) {
        for (MateInventoryLockLogAddRequest request : requests) {
            MateInventoryLockLog mateInventoryLockLog = mateInventoryLockLogMapper.selectOne(
                    new LambdaQueryWrapper<MateInventoryLockLog>()
                            .eq(MateInventoryLockLog::getOrderType, request.getOrderType())
                            .eq(MateInventoryLockLog::getMateInventoryId, request.getMateInventoryId())
                            .eq(MateInventoryLockLog::getSourceOrderNo, request.getSourceOrderNo())
                            .eq(MateInventoryLockLog::getLockStatus, MateInventoryLockLogLockStatusEnum.S1.getIntValue())
                            .eq(MateInventoryLockLog::getSourceDetailOrderNo, request.getSourceDetailOrderNo()));
            if (mateInventoryLockLog == null) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "无对应的库存锁定记录，不能释放锁定库存");
            }
            MateInventory mateInventory = mateInventoryMapper.selectById(request.getMateInventoryId());
            if (mateInventory.getLockQty() < request.getLockQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "释放锁定数量超过已锁数量，不能操作");
            }
            mateInventoryLockLog.setLockStatus(MateInventoryLockLogLockStatusEnum.S2.getIntValue());
            mateInventoryLockLog.setLockQty(mateInventoryLockLog.getLockQty() - request.getLockQty());
            mateInventoryLockLogMapper.updateById(mateInventoryLockLog);
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, request.getMateInventoryId())
                    .set(MateInventory::getLockQty, mateInventory.getLockQty() - request.getLockQty())
                    .set(MateInventory::getAvailableQty, mateInventory.getAvailableQty() + request.getLockQty())
            );
        }
    }


    /**
     * 采购退货出库，预售出库，退货出库, 调拨出库, 扣减锁定的库存
     */
    @Transactional(rollbackFor = Exception.class)
    public void t12OrT42OrT72OrT32(LogisticsTraceOrder traceOrder, List<LogisticsTraceApplyOrder> applyOrderList,
                                   List<LogisticsTraceApplyDetailOrder> applyDetailOrderList,
                                   List<LogisticsTraceDetailOrder> detailOrderList) {
        List<Object[]> traceDetailOrderList = convert(applyOrderList, applyDetailOrderList, detailOrderList);
        // 出库单
        // 创建出库明细
        // 库存调整
        MateInventoryOrder mateInventoryOrder = new MateInventoryOrder();
        mateInventoryOrder.setOrderNo(idGenerator.ck());
        mateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        mateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizOrderNo(traceOrder.getOrderNo());
        mateInventoryOrder.setSourceOrderType(traceOrder.getSourceOrderType());
        mateInventoryOrder.setCreateUserCode(traceOrder.getCreateUserCode());
        mateInventoryOrder.setCreateUserName(traceOrder.getCreateUserName());
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        int index = 0;
        for (Object[] array : traceDetailOrderList) {
            LogisticsTraceApplyOrder applyOrder = (LogisticsTraceApplyOrder) array[0];
            LogisticsTraceApplyDetailOrder applyDetailOrder = (LogisticsTraceApplyDetailOrder) array[1];
            LogisticsTraceDetailOrder traceDetailOrder = (LogisticsTraceDetailOrder) array[2];
            if (index == 0) {
                mateInventoryOrder.setSubject(applyOrder.getSubject());
                mateInventoryOrder.setSubWarehouseCode(traceDetailOrder.getSubWarehouseCode());
                mateInventoryOrderMapper.insert(mateInventoryOrder);
            }
            MateInventory mateInventory = mateInventoryMapper.selectById(traceDetailOrder.getMateInventoryId());
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                    new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getMateSku, mateInventory.getMateSku())
                            .eq(MatePurchaseCode::getPurchaseCode, mateInventory.getPurchaseCode()));
            MateInventoryDetailOrder mateInventoryDetailOrder = new MateInventoryDetailOrder();
            mateInventoryDetailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
            mateInventoryDetailOrder.setSourceOrderNo(applyOrder.getSourceOrderNo());
            mateInventoryDetailOrder.setSourceDetailOrderNo(applyOrder.getSourceDetailOrderNo());
            mateInventoryDetailOrder.setMateInventoryId(mateInventory.getId());
            mateInventoryDetailOrder.setMateSku(mateInventory.getMateSku());
            mateInventoryDetailOrder.setInventoryType(mateInventory.getInventoryType());
            mateInventoryDetailOrder.setSaleSubChannel(mateInventory.getSaleSubChannel());
            mateInventoryDetailOrder.setPurchaseCode(mateInventory.getPurchaseCode());
            mateInventoryDetailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            mateInventoryDetailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            mateInventoryDetailOrder.setProductDate(matePurchaseCode.getProductDate());
            mateInventoryDetailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            mateInventoryDetailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            mateInventoryDetailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            mateInventoryDetailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            mateInventoryDetailOrder.setActualInQty(traceDetailOrder.getActualInQty());
            mateInventoryDetailOrderList.add(mateInventoryDetailOrder);
            // 对应锁定lock更新
            LambdaQueryWrapper<MateInventoryLockLog> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper
                    .eq(MateInventoryLockLog::getOrderType, mateInventoryOrder.getOrderType())
                    .eq(MateInventoryLockLog::getMateInventoryId, mateInventoryDetailOrder.getMateInventoryId())
                    .eq(MateInventoryLockLog::getSourceOrderNo, mateInventoryDetailOrder.getSourceOrderNo())
                    .eq(MateInventoryLockLog::getLockStatus, MateInventoryLockLogLockStatusEnum.S1.getIntValue())
                    .eq(MateInventoryLockLog::getSourceDetailOrderNo, mateInventoryDetailOrder.getSourceDetailOrderNo());
            MateInventoryLockLog mateInventoryLockLog = mateInventoryLockLogMapper.selectOne(queryWrapper);
            if (mateInventoryLockLog == null) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "无对应的库存锁定记录，不能扣减库存");
            }
            mateInventoryLockLog.setLockStatus(MateInventoryLockLogLockStatusEnum.S2.getIntValue());
            mateInventoryLockLog.setLockQty(mateInventoryLockLog.getLockQty() - mateInventoryDetailOrder.getActualInQty());
            mateInventoryLockLogMapper.updateById(mateInventoryLockLog);
            if (mateInventory.getLockQty() < mateInventoryDetailOrder.getActualInQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "锁定库存不足，无法扣减库存");
            }
            // 更新库存数量, 扣减锁定数量 锁定数量和跟进数量可能不符
            // 实际库存数量 = 当前可用数量 + 锁定数量 - 跟进数量
            // 锁定数量 = 当前锁定数量 - 锁定数量
            mateInventoryMapper.update(null,
                    new LambdaUpdateWrapper<MateInventory>()
                            .eq(MateInventory::getId, mateInventory.getId())
                            .set(MateInventory::getAvailableQty,
                                    mateInventory.getAvailableQty() + mateInventoryDetailOrder.getActualInQty() - traceDetailOrder.getActualInQty())
                            .set(MateInventory::getLockQty, mateInventory.getLockQty() - mateInventoryDetailOrder.getActualInQty())
            );
            index++;
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
    }

    /**
     * 库存矫正，调整库存
     *
     * @param list
     */
    public Map<Long, MateInventory> adjustMateInventory(MateInventoryAdjustLog adjustLog, List<MateInventoryAdjustLogDetail> list) {
        Map<Long, MateInventory> result = new HashMap<>();
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        MateInventoryOrder outMateInventoryOrder = new MateInventoryOrder();
        outMateInventoryOrder.setOrderNo(idGenerator.ck());
        outMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        outMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T2.getIntValue());
        outMateInventoryOrder.setBizOrderNo(adjustLog.getOrderNo());
        outMateInventoryOrder.setSourceOrderType(SubjectEnum.T82.getCode());
        outMateInventoryOrder.setSubject(SubjectEnum.T82.getCode());
        outMateInventoryOrder.setSubWarehouseCode(adjustLog.getSubWarehouseCode());
        outMateInventoryOrder.setCreateUserCode(adjustLog.getCreateUserCode());
        outMateInventoryOrder.setCreateUserName(adjustLog.getCreateUserName());
        mateInventoryOrderMapper.insert(outMateInventoryOrder);
        MateInventoryOrder inMateInventoryOrder = new MateInventoryOrder();
        inMateInventoryOrder.setOrderNo(idGenerator.rk());
        inMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        inMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T2.getIntValue());
        inMateInventoryOrder.setBizOrderNo(adjustLog.getOrderNo());
        inMateInventoryOrder.setSourceOrderType(SubjectEnum.T81.getCode());
        inMateInventoryOrder.setSubject(SubjectEnum.T81.getCode());
        inMateInventoryOrder.setSubWarehouseCode(adjustLog.getSubWarehouseCode());
        inMateInventoryOrder.setCreateUserCode(adjustLog.getCreateUserCode());
        inMateInventoryOrder.setCreateUserName(adjustLog.getCreateUserName());
        mateInventoryOrderMapper.insert(inMateInventoryOrder);
        for (MateInventoryAdjustLogDetail request : list) {
            // 原库存扣减
            MateInventory outMateInventory = mateInventoryMapper.selectById(request.getBeforeMateInventoryId());
            if (outMateInventory.getAvailableQty() < request.getAdjustQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法调整数量");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, request.getBeforeMateInventoryId())
                    .set(MateInventory::getAvailableQty, outMateInventory.getAvailableQty() - request.getAdjustQty())
            );
            // 创建新的采购批次，创建新的库存批次
            // 调整的批次库存增加
            MatePurchaseCode matePurchaseCode = new MatePurchaseCode();
            matePurchaseCode.setMateSku(outMateInventory.getMateSku());
            matePurchaseCode.setPurchaseCode(idGenerator.pc());
            matePurchaseCode.setPurchaseOrderNo(request.getAdjustPurchaseOrderNo());
            matePurchaseCode.setPurchaseDetailOrderNo(request.getAdjustPurchaseDetailOrderNo());
            matePurchaseCode.setCostPrice(request.getAdjustCostPrice());
            matePurchaseCode.setProduceCode(request.getAdjustProduceCode());
            matePurchaseCode.setCountryOfOrigin(request.getAdjustCountryOfOrigin());
            matePurchaseCode.setProductDate(request.getAdjustProductDate());
            matePurchaseCode.setExpireDate(request.getAdjustExpireDate());
            matePurchaseCode.setType(PurchaseCodeTypeEnum.T2.getIntValue());
            matePurchaseCode.setCreateTime(request.getAdjustRkTime().toInstant().atZone(ZoneId.of("GMT+8")).toLocalDateTime());
            matePurchaseCodeMapper.insert(matePurchaseCode);
            MateInventory inMateInventory = new MateInventory();
            inMateInventory.setMateSku(outMateInventory.getMateSku());
            inMateInventory.setSubWarehouseCode(adjustLog.getSubWarehouseCode());
            inMateInventory.setPurchaseCode(matePurchaseCode.getPurchaseCode());
            inMateInventory.setInventoryType(outMateInventory.getInventoryType());
            inMateInventory.setSaleSubChannel(outMateInventory.getSaleSubChannel());
            inMateInventory.setAvailableQty(request.getAdjustQty());
            inMateInventory.setLockQty(0);
            inMateInventory.setOnPassageQty(0);
            mateInventoryMapper.insert(inMateInventory);
            result.put(request.getId(), inMateInventory);
            mateInventoryDetailOrderList.add(createAdjust(adjustLog, request, outMateInventory, outMateInventoryOrder));
            mateInventoryDetailOrderList.add(createAdjust(adjustLog, request, inMateInventory, inMateInventoryOrder));
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return result;
    }

    private MateInventoryDetailOrder createAdjust(MateInventoryAdjustLog adjustLog,
                                                  MateInventoryAdjustLogDetail adjustLogDetail,
                                                  MateInventory mateInventory,
                                                  MateInventoryOrder mateInventoryOrder) {
        MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                new LambdaQueryWrapper<MatePurchaseCode>()
                        .eq(MatePurchaseCode::getMateSku, mateInventory.getMateSku())
                        .eq(MatePurchaseCode::getPurchaseCode, mateInventory.getPurchaseCode()));
        MateInventoryDetailOrder detailOrder = new MateInventoryDetailOrder();
        detailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
        detailOrder.setSourceOrderNo(adjustLog.getOrderNo());
        detailOrder.setSourceDetailOrderNo(adjustLogDetail.getOrderNo() + adjustLogDetail.getId());
        detailOrder.setMateInventoryId(mateInventory.getId());
        detailOrder.setMateSku(mateInventory.getMateSku());
        detailOrder.setInventoryType(mateInventory.getInventoryType());
        detailOrder.setSaleSubChannel(mateInventory.getSaleSubChannel());
        detailOrder.setPurchaseCode(mateInventory.getPurchaseCode());
        detailOrder.setProduceCode(matePurchaseCode.getProduceCode());
        detailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
        detailOrder.setProductDate(matePurchaseCode.getProductDate());
        detailOrder.setExpireDate(matePurchaseCode.getExpireDate());
        detailOrder.setActualInQty(adjustLogDetail.getAdjustQty());
        detailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
        detailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
        detailOrder.setCostPrice(matePurchaseCode.getCostPrice());
        return detailOrder;
    }

    /**
     * 库存拆卸，调整库存
     */
    public Map<Long, Long> cxMateInventory(MateInventoryCxLog mateInventoryCxLog,
                                           List<MateInventoryCxDetailLogInfo> mateInventoryCxDetailLogInfoList) {
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        MateInventoryOrder outMateInventoryOrder = new MateInventoryOrder();
        outMateInventoryOrder.setOrderNo(idGenerator.ck());
        outMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        outMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T3.getIntValue());
        outMateInventoryOrder.setBizOrderNo(mateInventoryCxLog.getOrderNo());
        outMateInventoryOrder.setSourceOrderType(SubjectEnum.T102.getCode());
        outMateInventoryOrder.setSubject(SubjectEnum.T102.getCode());
        outMateInventoryOrder.setSubWarehouseCode(mateInventoryCxLog.getSubWarehouseCode());
        outMateInventoryOrder.setCreateUserCode(mateInventoryCxLog.getCreateUserCode());
        outMateInventoryOrder.setCreateUserName(mateInventoryCxLog.getCreateUserName());
        mateInventoryOrderMapper.insert(outMateInventoryOrder);
        MateInventoryOrder inMateInventoryOrder = new MateInventoryOrder();
        inMateInventoryOrder.setOrderNo(idGenerator.rk());
        inMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        inMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T3.getIntValue());
        inMateInventoryOrder.setBizOrderNo(mateInventoryCxLog.getOrderNo());
        inMateInventoryOrder.setSourceOrderType(SubjectEnum.T101.getCode());
        inMateInventoryOrder.setSubject(SubjectEnum.T101.getCode());
        inMateInventoryOrder.setSubWarehouseCode(mateInventoryCxLog.getSubWarehouseCode());
        inMateInventoryOrder.setCreateUserCode(mateInventoryCxLog.getCreateUserCode());
        inMateInventoryOrder.setCreateUserName(mateInventoryCxLog.getCreateUserName());
        mateInventoryOrderMapper.insert(inMateInventoryOrder);
        Map<Long, Long> detailLogAfterMateInventoryIdMap = new HashMap<>();
        for (MateInventoryCxDetailLogInfo cxDetailLogInfo : mateInventoryCxDetailLogInfoList) {
            // 出库
            // 被拆商品库存可用数量和总库存数量减少
            MateInventory outMateInventory = mateInventoryMapper.selectById(cxDetailLogInfo.getBeforeMateInventoryId());
            if (outMateInventory.getAvailableQty() < cxDetailLogInfo.getBeforeQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法被拆卸");
            }
            LambdaUpdateWrapper<MateInventory> beforeMateInventoryUpdateWrapper = new LambdaUpdateWrapper<>();
            beforeMateInventoryUpdateWrapper.eq(MateInventory::getId, cxDetailLogInfo.getBeforeMateInventoryId());
            beforeMateInventoryUpdateWrapper.set(MateInventory::getAvailableQty,
                    outMateInventory.getAvailableQty() - cxDetailLogInfo.getBeforeQty());
            mateInventoryMapper.update(null, beforeMateInventoryUpdateWrapper);

            // 入库
            // 拆后商品库存可用数量和总库存数量增加
            // 先查询拆后的采购批次
            MatePurchaseCode afterMatePurchaseCode = matePurchaseCodeMapper
                    .selectOne(new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getPurchaseCode, outMateInventory.getPurchaseCode())
                            .eq(MatePurchaseCode::getMateSku, cxDetailLogInfo.getAfterMateSku())
                            .eq(MatePurchaseCode::getIsDeleted, false)
                    );
            MatePurchaseCode beforeMatePurchaseCode = matePurchaseCodeMapper
                    .selectOne(new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getPurchaseCode, outMateInventory.getPurchaseCode())
                            .eq(MatePurchaseCode::getMateSku, cxDetailLogInfo.getBeforeMateSku())
                            .eq(MatePurchaseCode::getIsDeleted, false)
                    );
            if (afterMatePurchaseCode == null) {
                afterMatePurchaseCode = new MatePurchaseCode();
                afterMatePurchaseCode.setMateSku(cxDetailLogInfo.getAfterMateSku());
                afterMatePurchaseCode.setPurchaseCode(beforeMatePurchaseCode.getPurchaseCode());
                afterMatePurchaseCode.setPurchaseOrderNo(beforeMatePurchaseCode.getPurchaseOrderNo());
                afterMatePurchaseCode.setPurchaseDetailOrderNo(beforeMatePurchaseCode.getPurchaseDetailOrderNo());
                afterMatePurchaseCode.setCostPrice(beforeMatePurchaseCode.getCostPrice()
                        .divide(new BigDecimal(cxDetailLogInfo.getChaiQty()), 6, RoundingMode.HALF_UP));
                afterMatePurchaseCode.setProduceCode(beforeMatePurchaseCode.getProduceCode());
                afterMatePurchaseCode.setCountryOfOrigin(beforeMatePurchaseCode.getCountryOfOrigin());
                afterMatePurchaseCode.setProductDate(beforeMatePurchaseCode.getProductDate());
                afterMatePurchaseCode.setExpireDate(beforeMatePurchaseCode.getExpireDate());
                afterMatePurchaseCode.setCreateTime(beforeMatePurchaseCode.getCreateTime());
                afterMatePurchaseCode.setType(PurchaseCodeTypeEnum.T3.getIntValue());
                matePurchaseCodeMapper.insert(afterMatePurchaseCode);
            }
            LambdaQueryWrapper<MateInventory> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MateInventory::getIsDeleted, false);
            queryWrapper.eq(MateInventory::getSubWarehouseCode, mateInventoryCxLog.getSubWarehouseCode());
            queryWrapper.eq(MateInventory::getMateSku, cxDetailLogInfo.getAfterMateSku());
            queryWrapper.eq(MateInventory::getInventoryType, outMateInventory.getInventoryType());
            queryWrapper.eq(MateInventory::getPurchaseCode, outMateInventory.getPurchaseCode());
            queryWrapper.eq(MateInventory::getSaleSubChannel, outMateInventory.getSaleSubChannel());
            MateInventory inMateInventory = mateInventoryMapper.selectOne(queryWrapper);
            int inQty = cxDetailLogInfo.getChaiQty() * cxDetailLogInfo.getBeforeQty();
            if (inMateInventory == null) {
                inMateInventory = new MateInventory();
                inMateInventory.setMateSku(cxDetailLogInfo.getAfterMateSku());
                inMateInventory.setSubWarehouseCode(mateInventoryCxLog.getSubWarehouseCode());
                inMateInventory.setPurchaseCode(outMateInventory.getPurchaseCode());
                inMateInventory.setInventoryType(outMateInventory.getInventoryType());
                inMateInventory.setSaleSubChannel(outMateInventory.getSaleSubChannel());
                inMateInventory.setAvailableQty(inQty);
                inMateInventory.setLockQty(0);
                inMateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(inMateInventory);
            } else {
                mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                        .eq(MateInventory::getId, inMateInventory.getId())
                        .set(MateInventory::getAvailableQty, inMateInventory.getAvailableQty() + inQty)
                );
            }
            mateInventoryDetailOrderList.add(createCxDetail(mateInventoryCxLog, cxDetailLogInfo, outMateInventory,
                    beforeMatePurchaseCode, cxDetailLogInfo.getBeforeQty(), outMateInventoryOrder));
            mateInventoryDetailOrderList.add(createCxDetail(mateInventoryCxLog, cxDetailLogInfo, inMateInventory,
                    afterMatePurchaseCode, inQty, inMateInventoryOrder));
            detailLogAfterMateInventoryIdMap.put(cxDetailLogInfo.getId(), inMateInventory.getId());
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return detailLogAfterMateInventoryIdMap;
    }

    private MateInventoryDetailOrder createCxDetail(MateInventoryCxLog mateInventoryCxLog,
                                                    MateInventoryCxDetailLogInfo mateInventoryCxDetailLog,
                                                    MateInventory mateInventory,
                                                    MatePurchaseCode matePurchaseCode,
                                                    int qty,
                                                    MateInventoryOrder mateInventoryOrder) {
        MateInventoryDetailOrder detailOrder = new MateInventoryDetailOrder();
        detailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
        detailOrder.setSourceOrderNo(mateInventoryCxLog.getOrderNo());
        detailOrder.setSourceDetailOrderNo(mateInventoryCxLog.getOrderNo() + mateInventoryCxDetailLog.getId());
        detailOrder.setMateInventoryId(mateInventory.getId());
        detailOrder.setMateSku(mateInventory.getMateSku());
        detailOrder.setInventoryType(mateInventory.getInventoryType());
        detailOrder.setSaleSubChannel(mateInventory.getSaleSubChannel());
        detailOrder.setPurchaseCode(mateInventory.getPurchaseCode());
        detailOrder.setActualInQty(qty);
        detailOrder.setProduceCode(matePurchaseCode.getProduceCode());
        detailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
        detailOrder.setProductDate(matePurchaseCode.getProductDate());
        detailOrder.setExpireDate(matePurchaseCode.getExpireDate());
        detailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
        detailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
        detailOrder.setCostPrice(matePurchaseCode.getCostPrice());
        return detailOrder;
    }

    /**
     * 调拨入库 创建在途 库存账目没有新增，有则增加在途数量
     */
    @Transactional(rollbackFor = Exception.class)
    public void t31Apply(LogisticsTraceOrder traceOrder, List<LogisticsTraceApplyOrder> applyOrderList,
                         List<LogisticsTraceApplyDetailOrder> applyDetailOrderList,
                         List<LogisticsTraceDetailOrder> detailOrderList) {
        List<Object[]> traceDetailOrderList = convert(applyOrderList, applyDetailOrderList, detailOrderList);
        List<MateInventoryLockLogAddRequest> mateInventoryLockLogAddRequestList = new ArrayList<>();
        for (Object[] array : traceDetailOrderList) {
            LogisticsTraceApplyOrder applyOrder = (LogisticsTraceApplyOrder) array[0];
            LogisticsTraceApplyDetailOrder applyDetailOrder = (LogisticsTraceApplyDetailOrder) array[1];
            LogisticsTraceDetailOrder outTraceDetailOrder = (LogisticsTraceDetailOrder) array[2];
            MateInventory outMateInventory = mateInventoryMapper.selectById(outTraceDetailOrder.getMateInventoryId());
            MateInventory inMateInventory = mateInventoryMapper.selectOne(new LambdaQueryWrapper<MateInventory>()
                    .eq(MateInventory::getIsDeleted, false)
                    .eq(MateInventory::getSubWarehouseCode, applyOrder.getTargetSubWarehouseCode())
                    .eq(MateInventory::getMateSku, applyOrder.getMateSku())
                    .eq(MateInventory::getSaleSubChannel, outMateInventory.getSaleSubChannel())
                    .eq(MateInventory::getInventoryType, outMateInventory.getInventoryType())
                    .eq(MateInventory::getPurchaseCode, outMateInventory.getPurchaseCode())
            );
            if (inMateInventory == null) {
                inMateInventory = new MateInventory();
                inMateInventory.setMateSku(outMateInventory.getMateSku());
                inMateInventory.setSubWarehouseCode(applyOrder.getTargetSubWarehouseCode());
                inMateInventory.setPurchaseCode(outMateInventory.getPurchaseCode());
                inMateInventory.setInventoryType(outMateInventory.getInventoryType());
                inMateInventory.setSaleSubChannel(outMateInventory.getSaleSubChannel());
                inMateInventory.setAvailableQty(0);
                inMateInventory.setLockQty(0);
                inMateInventory.setOnPassageQty(outTraceDetailOrder.getActualInQty());
                mateInventoryMapper.insert(inMateInventory);
            } else {
                Integer onPassageQty = inMateInventory.getOnPassageQty() + outTraceDetailOrder.getActualInQty();
                mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                        .eq(MateInventory::getId, inMateInventory.getId())
                        .set(MateInventory::getOnPassageQty, onPassageQty));
            }
            MateInventoryLockLogAddRequest addRequest = new MateInventoryLockLogAddRequest();
            addRequest.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
            addRequest.setSourceOrderNo(applyOrder.getSourceOrderNo());
            addRequest.setSourceDetailOrderNo(applyOrder.getSourceDetailOrderNo());
            addRequest.setSourceOrderType(SubjectEnum.T31.getCode());
            addRequest.setSubject(SubjectEnum.T31.getCode());
            addRequest.setMateInventoryId(inMateInventory.getId());
            addRequest.setLockQty(outTraceDetailOrder.getActualInQty());
            mateInventoryLockLogAddRequestList.add(addRequest);
        }
        mateInventoryLockLogService.batchSave(mateInventoryLockLogAddRequestList);
    }


    /**
     * 调拨在途扣减
     */
    public void t31ReleaseLock(LogisticsTraceOrder traceOrder, List<LogisticsTraceApplyOrder> applyOrderList,
                               List<LogisticsTraceApplyDetailOrder> applyDetailOrderList,
                               List<LogisticsTraceDetailOrder> detailOrderList) {
        List<Object[]> traceDetailOrderList = convert(applyOrderList, applyDetailOrderList, detailOrderList.stream()
                .filter(detailOrder -> LogisticsTraceDetailOrderTypeEnum.T2.eq(detailOrder.getOrderType()))
                .collect(Collectors.toList()));
        // 先把原在途库存撤销
        for (Object[] array : traceDetailOrderList) {
            LogisticsTraceApplyOrder applyOrder = (LogisticsTraceApplyOrder) array[0];
            LogisticsTraceApplyDetailOrder applyDetailOrder = (LogisticsTraceApplyDetailOrder) array[1];
            LogisticsTraceDetailOrder traceDetailOrder = (LogisticsTraceDetailOrder) array[2];
            MateInventory outMateInventory = mateInventoryMapper.selectById(traceDetailOrder.getMateInventoryId());
            MateInventory inMateInventory = mateInventoryMapper.selectOne(new LambdaQueryWrapper<MateInventory>()
                    .eq(MateInventory::getIsDeleted, false)
                    .eq(MateInventory::getSubWarehouseCode, applyOrder.getTargetSubWarehouseCode())
                    .eq(MateInventory::getMateSku, applyOrder.getMateSku())
                    .eq(MateInventory::getSaleSubChannel, outMateInventory.getSaleSubChannel())
                    .eq(MateInventory::getInventoryType, outMateInventory.getInventoryType())
                    .eq(MateInventory::getPurchaseCode, outMateInventory.getPurchaseCode())
            );
            MateInventoryLockLog mateInventoryLockLog = mateInventoryLockLogMapper.selectOne(
                    new LambdaQueryWrapper<MateInventoryLockLog>()
                            .eq(MateInventoryLockLog::getOrderType, LogisticsTraceDetailOrderTypeEnum.T1.getIntValue())
                            .eq(MateInventoryLockLog::getSourceOrderNo, applyOrder.getSourceOrderNo())
                            .eq(MateInventoryLockLog::getSourceDetailOrderNo, applyOrder.getSourceDetailOrderNo())
                            .eq(MateInventoryLockLog::getMateInventoryId, inMateInventory.getId()));

            if (inMateInventory.getOnPassageQty() < mateInventoryLockLog.getLockQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "调拨入库申请在途数量小于实际库存在途数量，无法操作");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, inMateInventory.getId())
                    .set(MateInventory::getOnPassageQty, inMateInventory.getOnPassageQty() - mateInventoryLockLog.getLockQty()));
            mateInventoryLockLog.setLockQty(0);
            mateInventoryLockLog.setLockStatus(MateInventoryLockLogLockStatusEnum.S2.getIntValue());
            mateInventoryLockLogMapper.updateById(mateInventoryLockLog);
        }
    }

    /**
     * 调拨入库 入库确认, 这里需要入库明细
     */
    @Transactional(rollbackFor = Exception.class)
    public Pair<String, List<MateInventoryAutoAdjustItemModel>> t31Confirm(LogisticsTraceOrder traceOrder, List<LogisticsTraceApplyOrder> applyOrderList,
                                                                           List<LogisticsTraceApplyDetailOrder> applyDetailOrderList,
                                                                           List<LogisticsTraceDetailOrder> detailOrderList) {
        List<MateInventoryAutoAdjustItemModel> adjustItemModels = new ArrayList<>();
        // 先释放原先在途库存
        t31ReleaseLock(traceOrder, applyOrderList, applyDetailOrderList, detailOrderList);
        List<Object[]> traceDetailOrderList = convert(applyOrderList, applyDetailOrderList, detailOrderList.stream()
                .filter(detailOrder -> LogisticsTraceDetailOrderTypeEnum.T1.eq(detailOrder.getOrderType()))
                .collect(Collectors.toList()));
        // 创建入库单
        // 创建入库明细
        // 创建库存
        MateInventoryOrder mateInventoryOrder = new MateInventoryOrder();
        mateInventoryOrder.setOrderNo(idGenerator.rk());
        mateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T1.getIntValue());
        mateInventoryOrder.setBizOrderNo(traceOrder.getOrderNo());
        mateInventoryOrder.setSourceOrderType(SubjectEnum.T31.getCode());
        mateInventoryOrder.setCreateUserCode(traceOrder.getCreateUserCode());
        mateInventoryOrder.setCreateUserName(traceOrder.getCreateUserName());
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        int index = 0;
        String subWarehouseCode = null;
        for (Object[] array : traceDetailOrderList) {
            LogisticsTraceApplyOrder applyOrder = (LogisticsTraceApplyOrder) array[0];
            LogisticsTraceApplyDetailOrder applyDetailOrder = (LogisticsTraceApplyDetailOrder) array[1];
            LogisticsTraceDetailOrder traceDetailOrder = (LogisticsTraceDetailOrder) array[2];
            if (traceDetailOrder.getMateInventoryId() != null) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "入库已完成，不能重复操作");
            }
            if (index == 0) {
                mateInventoryOrder.setSubject(SubjectEnum.T31.getCode());
                mateInventoryOrder.setSubWarehouseCode(traceDetailOrder.getSubWarehouseCode());
                mateInventoryOrderMapper.insert(mateInventoryOrder);
            }
            subWarehouseCode = traceDetailOrder.getSubWarehouseCode();
            Integer inventoryType = traceDetailOrder.getInventoryType();
            String mateSku = traceDetailOrder.getMateSku();
            String purchaseCode = traceDetailOrder.getPurchaseCode();
            String saleSubChannel = applyOrder.getSaleSubChannel();
            Integer actualInQty = traceDetailOrder.getActualInQty();
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                    new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getMateSku, mateSku)
                            .eq(MatePurchaseCode::getPurchaseCode, purchaseCode));
            MateInventory mateInventory = mateInventoryMapper.selectOne(new LambdaQueryWrapper<MateInventory>()
                    .eq(MateInventory::getSubWarehouseCode, subWarehouseCode)
                    .eq(MateInventory::getMateSku, mateSku)
                    .eq(MateInventory::getInventoryType, inventoryType)
                    .eq(MateInventory::getPurchaseCode, purchaseCode)
                    .eq(MateInventory::getSaleSubChannel, saleSubChannel)
            );
            if (mateInventory == null) {
                mateInventory = new MateInventory();
                mateInventory.setMateSku(mateSku);
                mateInventory.setSubWarehouseCode(subWarehouseCode);
                mateInventory.setPurchaseCode(purchaseCode);
                mateInventory.setInventoryType(inventoryType);
                mateInventory.setSaleSubChannel(saleSubChannel);
                mateInventory.setAvailableQty(actualInQty);
                mateInventory.setLockQty(0);
                mateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(mateInventory);
            } else {
                mateInventoryMapper.update(null,
                        new LambdaUpdateWrapper<MateInventory>()
                                .eq(MateInventory::getId, mateInventory.getId())
                                .set(MateInventory::getAvailableQty, mateInventory.getAvailableQty() + actualInQty)
                );
            }
            MateInventoryDetailOrder mateInventoryDetailOrder = new MateInventoryDetailOrder();
            mateInventoryDetailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
            mateInventoryDetailOrder.setSourceOrderNo(applyOrder.getSourceOrderNo());
            mateInventoryDetailOrder.setSourceDetailOrderNo(applyOrder.getSourceDetailOrderNo());
            mateInventoryDetailOrder.setMateSku(mateSku);
            mateInventoryDetailOrder.setInventoryType(inventoryType);
            mateInventoryDetailOrder.setSaleSubChannel(saleSubChannel);
            mateInventoryDetailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            mateInventoryDetailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            mateInventoryDetailOrder.setProductDate(matePurchaseCode.getProductDate());
            mateInventoryDetailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            mateInventoryDetailOrder.setActualInQty(actualInQty);
            mateInventoryDetailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            mateInventoryDetailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            mateInventoryDetailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            mateInventoryDetailOrder.setPurchaseCode(matePurchaseCode.getPurchaseCode());
            mateInventoryDetailOrder.setMateInventoryId(mateInventory.getId());
            mateInventoryDetailOrderList.add(mateInventoryDetailOrder);
            // 跟进跟进明细表mateInventoryId, 采购批次
            logisticsTraceDetailOrderMapper.update(null, new LambdaUpdateWrapper<LogisticsTraceDetailOrder>()
                    .eq(LogisticsTraceDetailOrder::getId, traceDetailOrder.getId())
                    .set(LogisticsTraceDetailOrder::getMateInventoryId, mateInventory.getId())
                    .set(LogisticsTraceDetailOrder::getPurchaseCode, mateInventory.getPurchaseCode())
            );
            if (StringUtils.isNotBlank(traceDetailOrder.getProduceCode())
                    && !traceDetailOrder.getProduceCode().equals(matePurchaseCode.getProduceCode())) {
                // 生产批次不一致，需要矫正批次
                MateInventoryAutoAdjustItemModel itemModel = new MateInventoryAutoAdjustItemModel();
                itemModel.setBeforeMateInventory(mateInventoryDetailOrder);
                itemModel.setRealProduceCode(traceDetailOrder.getProduceCode());
                itemModel.setSourceOrderNo(mateInventoryDetailOrder.getSourceOrderNo());
                itemModel.setSourceDetailOrderNo(mateInventoryDetailOrder.getSourceDetailOrderNo());
                adjustItemModels.add(itemModel);
            }
            index++;
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return new Pair<>(subWarehouseCode, adjustItemModels);
    }

    /**
     * @param request
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public MateInventoryOutResponse outMateInventory(MateInventoryOutRequest request) {
        MateInventoryOrder mateInventoryOrder = new MateInventoryOrder();
        BeanUtils.copyProperties(request.getMateInventoryOrderInfo(), mateInventoryOrder);
        mateInventoryOrderMapper.insert(mateInventoryOrder);
        List<MateInventory> mateInventories = mateInventoryMapper.selectBatchIds(
                request.getMateInventoryDetailOrderInfoList().stream()
                        .map(MateInventoryDetailOrderInfo::getMateInventoryId).distinct().collect(Collectors.toList()));
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        Map<Long, Integer> qtyMap = new HashMap<>();
        for (MateInventoryDetailOrderInfo mateInventoryDetailOrderInfo : request.getMateInventoryDetailOrderInfoList()) {
            MateInventoryDetailOrder mateInventoryDetailOrder = new MateInventoryDetailOrder();
            BeanUtils.copyProperties(mateInventoryDetailOrderInfo, mateInventoryDetailOrder);
            mateInventoryDetailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
            mateInventoryDetailOrderList.add(mateInventoryDetailOrder);
            Integer qty = qtyMap.get(mateInventoryDetailOrder.getMateInventoryId());
            if (qty == null) {
                qtyMap.put(mateInventoryDetailOrder.getMateInventoryId(), mateInventoryDetailOrder.getActualInQty());
            } else {
                qtyMap.put(mateInventoryDetailOrder.getMateInventoryId(), mateInventoryDetailOrder.getActualInQty() + qty);
            }
        }
        for (MateInventory mateInventory : mateInventories) {
            Integer qty = qtyMap.get(mateInventory.getId());
            if (mateInventory.getAvailableQty() < qty) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "库存数量不足，无法扣减");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, mateInventory.getId())
                    .set(MateInventory::getAvailableQty, mateInventory.getAvailableQty() - qty)
            );
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return new MateInventoryOutResponse();
    }

    /**
     * 货主变更，调整库存
     *
     * @param changeLog
     */
    public Map<Long, Long> changeMateInventorySaleChannel(MateInventorySaleChannelChangeLog changeLog,
                                                          List<MateInventorySaleChannelChangeLogDetail> changeLogDetails) {
        Map<Long, Long> changeDetailMap = new HashMap<>();
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        MateInventoryOrder outMateInventoryOrder = new MateInventoryOrder();
        outMateInventoryOrder.setOrderNo(idGenerator.ck());
        outMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        outMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T6.getIntValue());
        outMateInventoryOrder.setBizOrderNo(changeLog.getOrderNo());
        outMateInventoryOrder.setSourceOrderType(SubjectEnum.T112.getCode());
        outMateInventoryOrder.setSubject(SubjectEnum.T112.getCode());
        outMateInventoryOrder.setSubWarehouseCode(changeLog.getSubWarehouseCode());
        outMateInventoryOrder.setCreateUserCode(changeLog.getCreateUserCode());
        outMateInventoryOrder.setCreateUserName(changeLog.getCreateUserName());
        mateInventoryOrderMapper.insert(outMateInventoryOrder);
        MateInventoryOrder inMateInventoryOrder = new MateInventoryOrder();
        inMateInventoryOrder.setOrderNo(idGenerator.rk());
        inMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        inMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T6.getIntValue());
        inMateInventoryOrder.setBizOrderNo(changeLog.getOrderNo());
        inMateInventoryOrder.setSourceOrderType(SubjectEnum.T111.getCode());
        inMateInventoryOrder.setSubject(SubjectEnum.T111.getCode());
        inMateInventoryOrder.setSubWarehouseCode(changeLog.getSubWarehouseCode());
        inMateInventoryOrder.setCreateUserCode(changeLog.getCreateUserCode());
        inMateInventoryOrder.setCreateUserName(changeLog.getCreateUserName());
        mateInventoryOrderMapper.insert(inMateInventoryOrder);
        for (MateInventorySaleChannelChangeLogDetail detail : changeLogDetails) {
            // 原库存扣减
            MateInventory outMateInventory = mateInventoryMapper.selectById(detail.getBeforeMateInventoryId());
            if (outMateInventory.getAvailableQty() < detail.getQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法变更货权");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, detail.getBeforeMateInventoryId())
                    .set(MateInventory::getAvailableQty, outMateInventory.getAvailableQty() - detail.getQty())
            );
            // 入库批次
            MateInventory inMateInventory = mateInventoryMapper.selectOne(
                    new LambdaQueryWrapper<MateInventory>()
                            .eq(MateInventory::getIsDeleted, false)
                            .eq(MateInventory::getSubWarehouseCode, changeLog.getSubWarehouseCode())
                            .eq(MateInventory::getMateSku, outMateInventory.getMateSku())
                            .eq(MateInventory::getInventoryType, outMateInventory.getInventoryType())
                            .eq(MateInventory::getPurchaseCode, outMateInventory.getPurchaseCode())
                            .eq(MateInventory::getSaleSubChannel, detail.getAfterSaleSubChannel())
            );
            if (inMateInventory == null) {
                inMateInventory = new MateInventory();
                inMateInventory.setMateSku(outMateInventory.getMateSku());
                inMateInventory.setSubWarehouseCode(changeLog.getSubWarehouseCode());
                inMateInventory.setPurchaseCode(outMateInventory.getPurchaseCode());
                inMateInventory.setInventoryType(outMateInventory.getInventoryType());
                inMateInventory.setSaleSubChannel(detail.getAfterSaleSubChannel());
                inMateInventory.setAvailableQty(detail.getQty());
                inMateInventory.setLockQty(0);
                inMateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(inMateInventory);
            } else {
                mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                        .eq(MateInventory::getId, inMateInventory.getId())
                        .set(MateInventory::getAvailableQty, inMateInventory.getAvailableQty() + detail.getQty())
                );
            }
            changeDetailMap.put(detail.getId(), inMateInventory.getId());
            mateInventoryDetailOrderList.add(createMateInventorySaleChannelChangeLog(changeLog, detail, outMateInventory, outMateInventoryOrder));
            mateInventoryDetailOrderList.add(createMateInventorySaleChannelChangeLog(changeLog, detail, inMateInventory, inMateInventoryOrder));
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return changeDetailMap;
    }

    private MateInventoryDetailOrder createMateInventorySaleChannelChangeLog(MateInventorySaleChannelChangeLog changeLog,
                                                                             MateInventorySaleChannelChangeLogDetail detail,
                                                                             MateInventory mateInventory,
                                                                             MateInventoryOrder mateInventoryOrder) {
        MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                new LambdaQueryWrapper<MatePurchaseCode>()
                        .eq(MatePurchaseCode::getMateSku, mateInventory.getMateSku())
                        .eq(MatePurchaseCode::getPurchaseCode, mateInventory.getPurchaseCode()));
        MateInventoryDetailOrder detailOrder = new MateInventoryDetailOrder();
        detailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
        detailOrder.setSourceOrderNo(changeLog.getOrderNo());
        detailOrder.setSourceDetailOrderNo(changeLog.getOrderNo() + detail.getId());
        detailOrder.setMateInventoryId(mateInventory.getId());
        detailOrder.setMateSku(mateInventory.getMateSku());
        detailOrder.setInventoryType(mateInventory.getInventoryType());
        detailOrder.setSaleSubChannel(mateInventory.getSaleSubChannel());
        detailOrder.setPurchaseCode(mateInventory.getPurchaseCode());
        detailOrder.setProduceCode(matePurchaseCode.getProduceCode());
        detailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
        detailOrder.setProductDate(matePurchaseCode.getProductDate());
        detailOrder.setExpireDate(matePurchaseCode.getExpireDate());
        detailOrder.setActualInQty(detail.getQty());
        detailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
        detailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
        detailOrder.setCostPrice(matePurchaseCode.getCostPrice());
        return detailOrder;
    }

    /**
     * 库存状态变更，调整库存
     *
     * @param changeLog
     */
    public Map<Long, Long> changeMateInventoryType(MateInventoryTypeChangeLog changeLog,
                                                   List<MateInventoryTypeChangeLogDetail> changeLogDetails) {
        Map<Long, Long> changeDetailMap = new HashMap<>();
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        MateInventoryOrder outMateInventoryOrder = new MateInventoryOrder();
        outMateInventoryOrder.setOrderNo(idGenerator.ck());
        outMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        outMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T7.getIntValue());
        outMateInventoryOrder.setBizOrderNo(changeLog.getOrderNo());
        outMateInventoryOrder.setSourceOrderType(SubjectEnum.T122.getCode());
        outMateInventoryOrder.setSubject(SubjectEnum.T122.getCode());
        outMateInventoryOrder.setSubWarehouseCode(changeLog.getSubWarehouseCode());
        outMateInventoryOrder.setCreateUserCode(changeLog.getCreateUserCode());
        outMateInventoryOrder.setCreateUserName(changeLog.getCreateUserName());
        mateInventoryOrderMapper.insert(outMateInventoryOrder);
        MateInventoryOrder inMateInventoryOrder = new MateInventoryOrder();
        inMateInventoryOrder.setOrderNo(idGenerator.rk());
        inMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        inMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T7.getIntValue());
        inMateInventoryOrder.setBizOrderNo(changeLog.getOrderNo());
        inMateInventoryOrder.setSourceOrderType(SubjectEnum.T121.getCode());
        inMateInventoryOrder.setSubject(SubjectEnum.T121.getCode());
        inMateInventoryOrder.setSubWarehouseCode(changeLog.getSubWarehouseCode());
        inMateInventoryOrder.setCreateUserCode(changeLog.getCreateUserCode());
        inMateInventoryOrder.setCreateUserName(changeLog.getCreateUserName());
        mateInventoryOrderMapper.insert(inMateInventoryOrder);
        for (MateInventoryTypeChangeLogDetail detail : changeLogDetails) {
            // 原库存扣减
            MateInventory outMateInventory = mateInventoryMapper.selectById(detail.getBeforeMateInventoryId());
            if (outMateInventory.getAvailableQty() < detail.getQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法变更库存状态");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, detail.getBeforeMateInventoryId())
                    .set(MateInventory::getAvailableQty, outMateInventory.getAvailableQty() - detail.getQty())
            );
            // 入库库存状态
            Integer inventoryType = MateInventoryTypeChangeLogChangeTypeEnum.C2.eq(changeLog.getChangeType()) ?
                    InventoryTypeEnum.ZP.getIntValue() : InventoryTypeEnum.CC.getIntValue();
            MateInventory inMateInventory = mateInventoryMapper.selectOne(
                    new LambdaQueryWrapper<MateInventory>()
                            .eq(MateInventory::getIsDeleted, false)
                            .eq(MateInventory::getSubWarehouseCode, changeLog.getSubWarehouseCode())
                            .eq(MateInventory::getMateSku, outMateInventory.getMateSku())
                            .eq(MateInventory::getInventoryType, inventoryType)
                            .eq(MateInventory::getPurchaseCode, outMateInventory.getPurchaseCode())
                            .eq(MateInventory::getSaleSubChannel, outMateInventory.getSaleSubChannel())
            );
            if (inMateInventory == null) {
                inMateInventory = new MateInventory();
                inMateInventory.setMateSku(outMateInventory.getMateSku());
                inMateInventory.setSubWarehouseCode(changeLog.getSubWarehouseCode());
                inMateInventory.setPurchaseCode(outMateInventory.getPurchaseCode());
                inMateInventory.setInventoryType(inventoryType);
                inMateInventory.setSaleSubChannel(outMateInventory.getSaleSubChannel());
                inMateInventory.setAvailableQty(detail.getQty());
                inMateInventory.setLockQty(0);
                inMateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(inMateInventory);
            } else {
                mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                        .eq(MateInventory::getId, inMateInventory.getId())
                        .set(MateInventory::getAvailableQty, inMateInventory.getAvailableQty() + detail.getQty())
                );
            }
            changeDetailMap.put(detail.getId(), inMateInventory.getId());
            mateInventoryDetailOrderList.add(createMateInventorySaleChannelChangeLog(changeLog, detail, outMateInventory, outMateInventoryOrder));
            mateInventoryDetailOrderList.add(createMateInventorySaleChannelChangeLog(changeLog, detail, inMateInventory, inMateInventoryOrder));
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return changeDetailMap;
    }

    private MateInventoryDetailOrder createMateInventorySaleChannelChangeLog(MateInventoryTypeChangeLog changeLog,
                                                                             MateInventoryTypeChangeLogDetail detail,
                                                                             MateInventory mateInventory,
                                                                             MateInventoryOrder mateInventoryOrder) {
        MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                new LambdaQueryWrapper<MatePurchaseCode>()
                        .eq(MatePurchaseCode::getMateSku, mateInventory.getMateSku())
                        .eq(MatePurchaseCode::getPurchaseCode, mateInventory.getPurchaseCode()));
        MateInventoryDetailOrder detailOrder = new MateInventoryDetailOrder();
        detailOrder.setMateInventoryOrderId(mateInventoryOrder.getId());
        detailOrder.setSourceOrderNo(changeLog.getOrderNo());
        detailOrder.setSourceDetailOrderNo(changeLog.getOrderNo() + detail.getId());
        detailOrder.setMateInventoryId(mateInventory.getId());
        detailOrder.setMateSku(mateInventory.getMateSku());
        detailOrder.setInventoryType(mateInventory.getInventoryType());
        detailOrder.setSaleSubChannel(mateInventory.getSaleSubChannel());
        detailOrder.setPurchaseCode(mateInventory.getPurchaseCode());
        detailOrder.setProduceCode(matePurchaseCode.getProduceCode());
        detailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
        detailOrder.setProductDate(matePurchaseCode.getProductDate());
        detailOrder.setExpireDate(matePurchaseCode.getExpireDate());
        detailOrder.setActualInQty(detail.getQty());
        detailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
        detailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
        detailOrder.setCostPrice(matePurchaseCode.getCostPrice());
        return detailOrder;
    }

    /**
     * 其他出库，调整库存
     *
     * @param changeLog
     */
    public void otherOut(MateInventoryOtherOutLog changeLog, List<MateInventoryOtherOutLogDetail> changeLogDetails) {
        Map<Long, Long> changeDetailMap = new HashMap<>();
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        MateInventoryOrder outMateInventoryOrder = new MateInventoryOrder();
        outMateInventoryOrder.setOrderNo(idGenerator.ck());
        outMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
        outMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T8.getIntValue());
        outMateInventoryOrder.setBizOrderNo(changeLog.getOrderNo());
        outMateInventoryOrder.setSourceOrderType(SubjectEnum.T132.getCode());
        outMateInventoryOrder.setSubject(SubjectEnum.T132.getCode());
        outMateInventoryOrder.setSubWarehouseCode(changeLog.getSubWarehouseCode());
        outMateInventoryOrder.setCreateUserCode(changeLog.getCreateUserCode());
        outMateInventoryOrder.setCreateUserName(changeLog.getCreateUserName());
        mateInventoryOrderMapper.insert(outMateInventoryOrder);
        for (MateInventoryOtherOutLogDetail detail : changeLogDetails) {
            // 原库存扣减
            MateInventory outMateInventory = mateInventoryMapper.selectById(detail.getMateInventoryId());
            if (outMateInventory.getAvailableQty() < detail.getQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法出库");
            }
            mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                    .eq(MateInventory::getId, detail.getMateInventoryId())
                    .set(MateInventory::getAvailableQty, outMateInventory.getAvailableQty() - detail.getQty())
            );
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                    new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getMateSku, outMateInventory.getMateSku())
                            .eq(MatePurchaseCode::getPurchaseCode, outMateInventory.getPurchaseCode()));
            MateInventoryDetailOrder detailOrder = new MateInventoryDetailOrder();
            detailOrder.setMateInventoryOrderId(outMateInventoryOrder.getId());
            detailOrder.setSourceOrderNo(changeLog.getOrderNo());
            detailOrder.setSourceDetailOrderNo(changeLog.getOrderNo() + detail.getId());
            detailOrder.setMateInventoryId(outMateInventory.getId());
            detailOrder.setMateSku(outMateInventory.getMateSku());
            detailOrder.setInventoryType(outMateInventory.getInventoryType());
            detailOrder.setSaleSubChannel(outMateInventory.getSaleSubChannel());
            detailOrder.setPurchaseCode(outMateInventory.getPurchaseCode());
            detailOrder.setActualInQty(detail.getQty());
            detailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            detailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            detailOrder.setProductDate(matePurchaseCode.getProductDate());
            detailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            detailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            detailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            detailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            mateInventoryDetailOrderList.add(detailOrder);
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
    }

    /**
     * 其他入库，调整库存
     */
    public Map<Long, MateInventory> otherIn(MateInventoryOtherInLog inLog, List<MateInventoryOtherInLogDetail> inLogDetails) {
        Map<Long, MateInventory> resultMap = new HashMap<>();
        List<MateInventoryDetailOrder> mateInventoryDetailOrderList = new ArrayList<>();
        MateInventoryOrder inMateInventoryOrder = new MateInventoryOrder();
        inMateInventoryOrder.setOrderNo(idGenerator.rk());
        inMateInventoryOrder.setOrderType(LogisticsTraceDetailOrderTypeEnum.T1.getIntValue());
        inMateInventoryOrder.setBizType(MateInventoryOrderBizTypeEnum.T9.getIntValue());
        inMateInventoryOrder.setBizOrderNo(inLog.getOrderNo());
        inMateInventoryOrder.setSourceOrderType(SubjectEnum.T131.getCode());
        inMateInventoryOrder.setSubject(SubjectEnum.T131.getCode());
        inMateInventoryOrder.setSubWarehouseCode(inLog.getSubWarehouseCode());
        inMateInventoryOrder.setCreateUserCode(inLog.getCreateUserCode());
        inMateInventoryOrder.setCreateUserName(inLog.getCreateUserName());
        mateInventoryOrderMapper.insert(inMateInventoryOrder);
        for (MateInventoryOtherInLogDetail detail : inLogDetails) {
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.getByMore(detail.getMateSku(), detail.getProduceCode(),
                    detail.getCostPrice().toString(), DateUtil.formatDate(detail.getRkTime()));
            boolean newMatePurchaseCode = matePurchaseCode == null;
            MateInventory inMateInventory = null;
            if (matePurchaseCode == null) {
                matePurchaseCode = new MatePurchaseCode();
                matePurchaseCode.setMateSku(detail.getMateSku());
                matePurchaseCode.setPurchaseCode(idGenerator.pc());
                matePurchaseCode.setPurchaseOrderNo("");
                matePurchaseCode.setPurchaseDetailOrderNo("");
                matePurchaseCode.setCostPrice(detail.getCostPrice());
                matePurchaseCode.setProduceCode(detail.getProduceCode());
                matePurchaseCode.setCountryOfOrigin(detail.getCountryOfOrigin());
                matePurchaseCode.setProductDate(detail.getProductDate());
                matePurchaseCode.setExpireDate(detail.getExpireDate());
                matePurchaseCode.setCreateTime(detail.getRkTime().toInstant().atZone(ZoneId.of("GMT+8")).toLocalDateTime());
                matePurchaseCode.setType(PurchaseCodeTypeEnum.T4.getIntValue());
                matePurchaseCodeMapper.insert(matePurchaseCode);
            }
            if (!newMatePurchaseCode) {
                inMateInventory = mateInventoryMapper.selectOne(new LambdaQueryWrapper<MateInventory>()
                        .eq(MateInventory::getSubWarehouseCode, inLog.getSubWarehouseCode())
                        .eq(MateInventory::getSaleSubChannel, inLog.getSaleSubChannel())
                        .eq(MateInventory::getMateSku, detail.getMateSku())
                        .eq(MateInventory::getPurchaseCode, matePurchaseCode.getPurchaseCode())
                        .eq(MateInventory::getInventoryType, detail.getInventoryType()));
            }
            if (inMateInventory == null) {
                inMateInventory = new MateInventory();
                inMateInventory.setMateSku(detail.getMateSku());
                inMateInventory.setSubWarehouseCode(inLog.getSubWarehouseCode());
                inMateInventory.setPurchaseCode(matePurchaseCode.getPurchaseCode());
                inMateInventory.setInventoryType(detail.getInventoryType());
                inMateInventory.setSaleSubChannel(inLog.getSaleSubChannel());
                inMateInventory.setAvailableQty(detail.getQty());
                inMateInventory.setLockQty(0);
                inMateInventory.setOnPassageQty(0);
                mateInventoryMapper.insert(inMateInventory);
            } else {
                mateInventoryMapper.update(null, new LambdaUpdateWrapper<MateInventory>()
                        .eq(MateInventory::getId, inMateInventory.getId())
                        .set(MateInventory::getAvailableQty, inMateInventory.getAvailableQty() + detail.getQty())
                );
            }
            MateInventoryDetailOrder detailOrder = new MateInventoryDetailOrder();
            detailOrder.setMateInventoryOrderId(inMateInventoryOrder.getId());
            detailOrder.setSourceOrderNo(inLog.getOrderNo());
            detailOrder.setSourceDetailOrderNo(inLog.getOrderNo() + detail.getId());
            detailOrder.setMateInventoryId(inMateInventory.getId());
            detailOrder.setMateSku(inMateInventory.getMateSku());
            detailOrder.setInventoryType(inMateInventory.getInventoryType());
            detailOrder.setSaleSubChannel(inMateInventory.getSaleSubChannel());
            detailOrder.setPurchaseCode(inMateInventory.getPurchaseCode());
            detailOrder.setActualInQty(detail.getQty());
            detailOrder.setProduceCode(matePurchaseCode.getProduceCode());
            detailOrder.setCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            detailOrder.setProductDate(matePurchaseCode.getProductDate());
            detailOrder.setExpireDate(matePurchaseCode.getExpireDate());
            detailOrder.setPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            detailOrder.setPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            detailOrder.setCostPrice(matePurchaseCode.getCostPrice());
            mateInventoryDetailOrderList.add(detailOrder);
            resultMap.put(detail.getId(), inMateInventory);
        }
        mateInventoryDetailOrderService.saveBatch(mateInventoryDetailOrderList);
        return resultMap;
    }
}
